package com.example.usbhidtool;

import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.AssetManager;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbRequest;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;

import com.easysocket.EasySocket;
import com.easysocket.entity.OriginReadData;
import com.easysocket.entity.SocketAddress;
import com.easysocket.interfaces.conn.SocketActionListener;
import com.example.usbhidtool.hid.DataPack;
import com.example.usbhidtool.hid.umessage.UMessage;
import com.example.usbhidtool.hid.umessage.UMessageCallBack;
import com.example.usbhidtool.hid.umessage.UMessageWithCallBack;
import com.example.usbhidtool.tcp.SocketManager;
import com.example.usbhidtool.utils.JsonUtils;
import com.example.usbhidtool.utils.TimeUtil;

import org.json.JSONObject;

import java.io.BufferedInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.concurrent.ConcurrentLinkedQueue;


public class MainActivityNew extends AppCompatActivity implements View.OnClickListener {

    private static final String INTENT_ACTION_GRANT_USB = "LIANGJILAIYE_GRANT_USB";
    //组件
    private TextView TVdevicestatus = null;
    private TextView TVdeviceversion = null;
    private TextView TVappversion = null;
    private TextView TVlinkstatus = null;
    private TextView TVClear = null;

    private Button btnSend1 = null;
    private Button btnSend2 = null;
    private Button btnSend3 = null;

    private EditText editRead = null;
    //标题栏
    private ActionBar actionBar = null;

    //当前发送内容
    private byte[] strCurrSend = new byte[0];

    //USB管理
    private enum UsbPermission {Unknown, Requested, Granted, Denied}

    ;

    private UsbManager usbManager = null;

    //接收USB设备插入后所发送消息的广播接收器
    private BroadcastReceiver broadcastReceiver;
    private PendingIntent penIntent = null;

    //针对某一个特定的USB PortA要用到的几个对象组合
    private UsbDevice deviceA = null;
    private UsbDeviceConnection connectionA = null;
    private UsbPermission usbPermissionA = UsbPermission.Unknown;

    private UsbInterface interfaceA = null;
    private UsbEndpoint epOut = null;
    private UsbEndpoint epIn = null;

    //最大包长度 : 511字节
    private final int MAXPacketSize = 512;
    private byte[] writeBuff;
    private byte[] readBuff;
    //todo
    //常用的buffer，使用directAlloc
    private ByteBuffer writeByteBuffer;
    private ByteBuffer readByteBuffer;

    //为真时退出监视Usb读取的线程
    private boolean bUsbReadExit = false;
    //读线程正在运行的标记
    private boolean bUsbReadRunning = false;
    //读写线程锁块
    private final String strUsbReadRunning = "LOCKREAD";
    private final String strUsbWriteRunning = "LOCKWRITE";
    //读线程中要使用的USB请求类
    private UsbRequest okUsbReq = null;

    private boolean bRefreshRead = false;//读取完成
    //todo
//    private boolean bRefreshWrite = true;//发送完成
    private boolean bRefreshExit = false;

    //写未完成
    private boolean bUsbWriteOK = true;

    //对开发板的控制传输操作后的返回值存放点(最多MAXPacketSize字节)
    private String liangjibuffer = "";
    private boolean bFile = false;
    private int nLength = 0;
    private int recFileLength = 0; //已经接收的文件长度
    private long lastFilePrintTime = 0;


    //消息队列
    private ConcurrentLinkedQueue<UMessage> MQ = new ConcurrentLinkedQueue();
    //空消息
    private UMessage emptyUMsg = new UMessage(new byte[0]);


    public enum DEVICESTATUS {
        UNKNOWN("未知", -4), NOTPASS("未信任", -3), NOTTRUST("未解锁", -2), NOTTAFFIRM("未同意", -1), LINKING("连接成功", 0), GETINFOING("获取信息开始", 1), GETINFOEND("获取信息结束", 2);
        // 成员变量
        private String name;
        private int index;

        // 构造方法
        private DEVICESTATUS(String name, int index) {
            this.name = name;
            this.index = index;
        }
        //接口方法

        public int getIndex() {
            return index;
        }

        public String getName() {
            return name;
        }

        /**
         * 根据code获取去value
         *
         * @param index
         * @return
         */
        public static String getValueByIndex(int index) {
            for (DEVICESTATUS platformFree : DEVICESTATUS.values()) {
                if (platformFree.getIndex() == index) {
                    return platformFree.getName();
                }
            }
            return "Unknown";
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TVdevicestatus = (TextView) findViewById(R.id.devicestatus);
        TVdeviceversion = (TextView) findViewById(R.id.deviceversion);
        TVappversion = (TextView) findViewById(R.id.appversion);
        TVlinkstatus = (TextView) findViewById(R.id.linkstatus);
        TVClear = findViewById(R.id.tv_clear);

        btnSend1 = (Button) findViewById(R.id.btnSend1);
        btnSend2 = (Button) findViewById(R.id.btnSend2);
        btnSend3 = (Button) findViewById(R.id.btnSend3);
//        btnSend[2] = (Button) findViewById(R.id.btnSend2);
//        btnSend[3] = (Button) findViewById(R.id.btnSend3);
//        btnSend[4] = (Button) findViewById(R.id.btnSend4);
//        btnSend[5] = (Button) findViewById(R.id.btnSend5);
//        btnSend[6] = (Button) findViewById(R.id.btnSend6);

        editRead = (EditText) findViewById(R.id.editlog);


        //注册按键动作监听器
        //入参为: View.OnClickListener 的接口实例,即 this
        btnSend1.setOnClickListener(this);
        btnSend2.setOnClickListener(this);
        btnSend3.setOnClickListener(this);
        TVClear.setOnClickListener(this);
//        btnSend[2].setOnClickListener(this);
//        btnSend[3].setOnClickListener(this);
//        btnSend[4].setOnClickListener(this);
//        btnSend[5].setOnClickListener(this);
//        btnSend[6].setOnClickListener(this);

        //不能弹出输入键盘
        editRead.setKeyListener(null);
        //不能取得输入焦点
        editRead.setFocusable(false);
        editRead.setFocusableInTouchMode(false);

        //修改标题栏文字内容
        actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.setTitle("USB HID调试工具");
        }

        //最大包长度MAXPackageSize
        readBuff = new byte[MAXPacketSize];
        writeBuff = new byte[MAXPacketSize];
        //todo
        writeByteBuffer = ByteBuffer.allocate(MAXPacketSize + 2);
        readByteBuffer = ByteBuffer.allocateDirect(MAXPacketSize);

        //清空退出USB读取线程的标记
        bUsbReadExit = false;
        bRefreshRead = false;
        bRefreshExit = false;

        //查找
        findChipList();
        //定义一个广播接收器, 当它收到特定的广播后会重新设置授权标记 usbPermission 的值
        broadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (intent.getAction().equals(INTENT_ACTION_GRANT_USB)) {
                    //需要判断用户是按下了: [确定] 或 [取消] 按键
                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                        //标记授权成功
                        updateUILog("收到广播: 已在授权界面取得USB运行期授权");
                    } else {
                        //标记授权未成功
                        updateUILog("收到广播: 未能在授权界面取得USB运行期授权");
                    }
                } else if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
                    //此广播能正常收到
                    //获取此USB设备信息。
                    UsbDevice ud = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    int nDID = ud.getDeviceId();
                    int nVID = ud.getVendorId();
                    int nPID = ud.getProductId();
                    updateUILog("收到广播: 刚插入USB设备->" + getChipType(nVID, nPID) +
                            " " + nDID +
                            " VID=" + nVID +
                            " PID=" + nPID + "");
                } else if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) {
                    //此广播能正常收到
                    //先执行关闭(因为设备突然拔掉,通讯很可能异常)
                    closeUsbPortA();
                    updateUILog(" Port设备异外关闭");
                    UsbDevice ud = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    int nDID = ud.getDeviceId();
                    int nVID = ud.getVendorId();
                    int nPID = ud.getProductId();
                    updateUILog("收到广播: 刚拔出USB设备->" + getChipType(nVID, nPID) +
                            " " + nDID +
                            " VID=" + nVID +
                            " PID=" + nPID);
                }
            }
        };
        //运行期授权的意图
        //获取一个能处理自定义广播发送的意图penIntent, 后面将通过penIntent发送一个自定义广播(类似调用sendBroadcast()方法) INTENT_ACTION_GRANT_USB 给广播接收器broadcastReceiver
        penIntent = PendingIntent.getBroadcast(this, 0, new Intent(INTENT_ACTION_GRANT_USB), 0);
        //意图过滤器filter
        IntentFilter filter = new IntentFilter();
        filter.addAction(INTENT_ACTION_GRANT_USB);
        filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
        filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);

        //注册此广播接收器,此广播接收器将只处理上面的filter定义的广播消息
        registerReceiver(broadcastReceiver, filter);
        //读线程正在运行的标记
        bUsbReadRunning = false;
    }

    private void initSocket() {
        //1、获取IP地址和端口号
        String address = "171.90.251.238";
        int port = 12595;
        SocketManager.createConnection(this, address, port);
        //socket行为监听
        EasySocket.getInstance().subscribeSocketAction(new SocketActionListener() {

            //连接成功
            @Override
            public void onSocketConnSuccess(SocketAddress socketAddress) {
                super.onSocketConnSuccess(socketAddress);
                Log.e("SOCKET", "SOCKET--->端口" + socketAddress.getIp() + ":" + socketAddress.getPort() + "=连接成功");
                //SocketManager.sendLoginMsg("24");
            }

            //连接失败
            @Override
            public void onSocketConnFail(SocketAddress socketAddress, boolean isNeedReconnect) {
                super.onSocketConnFail(socketAddress, isNeedReconnect);
                Log.e("SOCKET", "SOCKET--->端口" + socketAddress.getIp() + ":" + socketAddress.getPort() + "=连接失败");
            }

            @Override
            public void onSocketDisconnect(SocketAddress socketAddress, boolean isNeedReconnect) {
                super.onSocketDisconnect(socketAddress, isNeedReconnect);
                Log.e("SOCKET", "SOCKET--->端口" + socketAddress.getIp() + ":" + socketAddress.getPort() + "=socket连接被断开");
            }

            @Override
            public void onSocketResponse(SocketAddress socketAddress, OriginReadData originReadData) {
                super.onSocketResponse(socketAddress, originReadData);
                //处理消息
//                MessageHandle.handleMessage(socketAddress, originReadData);
            }

            @Override
            public void onSocketResponse(SocketAddress socketAddress, byte[] readData) {
                super.onSocketResponse(socketAddress, readData);
            }

            @Override
            public void onSocketResponse(SocketAddress socketAddress, String readData) {
                super.onSocketResponse(socketAddress, readData);
            }
        });

    }

    /**
     * 发送命令消息
     */
    public void sendCmdMsg(String str) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                byte[] a = DataPack.cmdPack(str);
                //todo
                updateUILog("准备发送命令：获取版本");
                UMessageWithCallBack message = new UMessageWithCallBack(a);
                message.setCallBack(sendSuccess -> {
                    if (sendSuccess == 1) {
                        updateUILog("获取版本命令成功" + str);
                    } else {
                        updateUILog("获取版本命令失败" + str);
                    }
                });
                MQ.add(message);
            }
        }).start();
    }

    public void sendDataMsg(byte[] str) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                byte[] a = DataPack.infoPack(false, str.length, str);//非文件信息头,不会带data值
                //todo
                updateUILog("准备发送命令：数据头");
                UMessageWithCallBack message = new UMessageWithCallBack(a);
                MQ.add(message);
                //设置回调
                message.setCallBack(sendSuccess -> {
                    if (sendSuccess == 1) {
                        //发送成功后回调
                        updateUILog("发送命令：数据头,成功 ==>数据长度=" + str.length);
                        int length = str.length;
                        int send_len = 0;
                        while (length > 0) {
                            if (length > MAXPacketSize - 4)//发送字节508个
                                send_len = MAXPacketSize - 4;
                            else
                                send_len = length;
                            byte[] send = new byte[send_len];
                            System.arraycopy(str, str.length - length, send, 0, send_len);//复制发送数据的片段
                            byte[] data = DataPack.dataPack(send);//非文件信息头,不会带data值
                            UMessageWithCallBack dataMsg = new UMessageWithCallBack(data);
                            dataMsg.setCallBack(sendSuccess1 -> {
                                if (sendSuccess1 == 1) {
                                    updateUILog("发送数据片成功,内容：" + new String(send) + "长度：" + send.length);
                                } else {
                                    updateUILog("获取数据片成功,内容：" + new String(send) + "长度：" + send.length);
                                }
                            });
                            MQ.add(dataMsg);
                            length -= send_len;
                        }
                    } else {
                        updateUILog("发送数据头失败: " + " 内容=>" + str);
                    }
                });
            }
        }).start();
    }

    /**
     * 发送文件
     */
    private void sendFile(String fileName) {
        try {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    sendFileReal(fileName);
                }
            }).start();
        } catch (Exception e) {
            updateUILog("发送文件线程异常：" + e.getMessage());
        }

    }

    private void sendFileReal(String fileName) {
        AssetManager manager = getAssets();
        try {
            //获取文件大小
            InputStream ins = manager.open(fileName);
            // 获取文件的字节数
            final int length = ins.available();
            ins.close();
            Log.e("tag", "文件大小：" + length);
            byte[] fileInfoBytes = "udcheck.app".getBytes("utf-8");
            byte[] fileInfo = DataPack.infoPack(true, length, fileInfoBytes);
            Log.e("tag", "发送文件头信息");
            updateUILog("发送文件头信息：" + "文件大小：" + length);
            UMessageWithCallBack fileHeaderMsg = new UMessageWithCallBack(fileInfo);
            fileHeaderMsg.setCallBack(new UMessageCallBack() {
                @Override
                public void onComplete(int sendSuccess) {
                    if (sendSuccess == 1) {
                        updateUILog("文件头信息发送成功");
                    }
                }
            });
            MQ.add(fileHeaderMsg);

            //通过流循环读取
            InputStream is = manager.open(fileName);
            BufferedInputStream bis = new BufferedInputStream(is);
            //一次读取508字节的数据
            byte[] buffer = new byte[MAXPacketSize - 4];
            int bytesRead = 0;
            Log.e("tag", "文件读写开始");
            updateUILog("开始发送文件片段,1秒打印一次");
            int readTimes = 0;
            long startTime = System.currentTimeMillis();
            long lastTime = System.currentTimeMillis();
            while ((bytesRead = bis.read(buffer)) != -1) {
                //如果队列数据大于1000，则休眠1000毫秒
                if (MQ.size() > 10000) {
                    try {
                        Thread.sleep(2);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                readTimes++;
                if (System.currentTimeMillis() - lastTime > 1000) {
                    lastTime = System.currentTimeMillis();
                    updateUILog(readTimes + "个文件片段已经加入队列" + TimeUtil.getHMSFormat(lastTime) + "\n");
                }
                if (bytesRead == MAXPacketSize - 4) {
                    UMessage uMessage = new UMessage(DataPack.dataPack(buffer));
                    MQ.add(uMessage);
                } else {
                    //最后一个包
                    byte[] lastPack = new byte[bytesRead];
                    System.arraycopy(buffer, 0, lastPack, 0, bytesRead);
                    UMessageWithCallBack uMessage = new UMessageWithCallBack(DataPack.dataPack(lastPack));
                    final int times = readTimes;
                    uMessage.setCallBack(sendSuccess -> {
                        if (sendSuccess == 1) {
                            updateUILog("文件最后片段发送成功,length:" + lastPack.length);
                            Log.e("tag", "==文件传输完成==");
                            updateUILog("==文件传输完成==" + "\n");
                            long endtime = System.currentTimeMillis();
                            Log.e("tag", "文件读写次数:" + times);
                            long cusTime = (endtime - startTime) / 1000;
                            long rate = length / 1024 / cusTime;
                            Log.e("tag", "文件传输耗时:" + cusTime + "秒");
                            updateUILog("文件传输耗时:" + cusTime + "秒");
                            Log.e("tag", "文件传输速率:" + rate + "kb/s");
                            updateUILog("文件传输速率:" + rate + "kb/s");
                        }
                    });
                    MQ.add(uMessage);
                }
            }
            is.close();

        } catch (Exception e) {
            updateUILog("发送文件异常" + e.getMessage());
        }
    }


    @Override
    public void onClick(View view) {
        try {
            switch (view.getId()) {
                case R.id.tv_clear:
                    editRead.setText("");
                    break;
                case R.id.btnSend1: {
                    String str = "V获取双版本";
                    sendCmdMsg(str);
                }
                break;
                case R.id.btnSend2: {
                    byte[] str = ("V发送数据fuoisdafpjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjweriasjfodsjfpajfdjisdpfajfifaojsdfsapfsj" +
                            "V发送数据fuoisdafpjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjweriasjfodsjfpajfdjisdpfajfifaojsdfsapfsjfd" +
                            "V发送数据fuoisdafpjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjweriasjfodsjfpajfdjisdpfajfifaojsdfsapfsjfd" +
                            "V发送数据fuoisdafpjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjweriasjfodsjfpajfdjisdpfajfifaojsdfsapfsjfd" +
                            "V发送数据fuoisdafpjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjweriasjfodsjfpajfdjisdpfajfifaojsdfsapfsjfd" +
                            "V发送数据fuoisdafpjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjweriasjfodsjfpajfdjisdpfajfifaojsdfsapfsjfd" +
                            "V发送数据fuoisdafpjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjweriasjfodsjfpajfdjisdpfajfifaojsdfsapfsjfd" +
                            "V发送数据fuoisdafpjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjweriasjfodsjfpajfdjisdpfajfifaojsdfsapfsjfd" +
                            "V发送数据fuoisdafpjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjweriasjfodsjfpajfdjisdpfajfifaojsdfsapfsjfd" +
                            "V发送数据fuoisdafpjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjweriasjfodsjfpajfdjisdpfajfifaojsdfsapfsjfd" +
                            "V发送数据fuoisdafpjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjweriasjfodsjfpajfdjisdpfajfifaojsdfsapfsjfd" +
                            "V发送数据fuoisdafpjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjweriasjfodsjfpajfdjisdpfajfifaojsdfsapfsjfdV发送数据fuoisdafpjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjweriasjfodsjfpajfdjisdpfajfifaojsdfsapfsjfd" +
                            "V发送数据fuoisdafpjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjweriasjfodsjfpajfdjisdpfajfifaojsdfsapfsjfd" +
                            "V发送数据fuoisdafpjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjweriasjfodsjfpajfdjisdpfajfifaojsdfsapfsjfd" +
                            "fd88888888end").getBytes("UTF-8");
                    sendDataMsg(str);
                    //writeString(a);
                }
                break;
                case R.id.btnSend3: {
                    //todo
                    sendFile("test_6.apk");
                }
                break;
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    //查找设备类列表
    private void findChipList() {

        int nDID = 0;
        int nVID = 0;
        int nPID = 0;

        //取回USB设备管理器
        usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);

        String strChip = "";
        for (UsbDevice v : usbManager.getDeviceList().values()) {

            nDID = v.getDeviceId();
            nVID = v.getVendorId();
            nPID = v.getProductId();

            //加入列表框
            //strChip = "Unknown" 不要加入
            strChip = getChipType(nVID, nPID);
            if (!strChip.equals("Unknown")) {
                editRead.append("已检测到:" + getChipType(nVID, nPID) + " " + nDID + " VID=" + nVID + "/PID=" + nPID + "\n");
                TVdevicestatus.setText("已检测到");
                openUsbPortA();
                break;
            }
        }
    }

    //打开USB总线A，成功返回真 （可能需要运行期授权）
    private void openUsbPortA() {
        //直接创建并启动一个匿名线程接口类的实例
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    if (execUsbPortA()) {
                        //启用读线程
                        //读线程正在运行的标记
                        if (bUsbReadRunning == false) {
                            bUsbReadExit = false;
                            okUsbReq = new UsbRequest();
                            //开始发送初始化命令与信息
                            sendCmdMsg("VINFO");
                            startWriteThread();
                            startReadThread();
                        }
                        //UI界面的按钮使能
                        runOnUiThread(() -> {
                            editRead.append("HID设备打开成功!\n");
                            editRead.append("监视Usb读取的线程已开启\n");
                            if (connectionA != null) {

                            }
                        });
                    } else {
                        updateUILog("HID设备初始化和打开失败!\n");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    //关闭USB总线A
    private void closeUsbPortA() {
        //释放接口
        //关闭连接
        if ((connectionA != null) && connectionA.getSerial() != "") {
            try {
                //主线程延时50ms后才关闭
                //Thread.sleep(50);
                connectionA.releaseInterface(interfaceA);
                interfaceA = null;
                connectionA.close();
                connectionA = null;
                deviceA = null;
                epOut = null;
                epIn = null;
                editRead.append("USB 设备已关闭!\n");
            } catch (Exception ignored) {
                ignored.printStackTrace();
            }
        }
    }

    /**
     * 开启读线程
     */
    private void startReadThread() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    int nSize = MAXPacketSize;
                    boolean bReadYes;
                    //todo 读数据专用请求
                    UsbRequest readRequest = new UsbRequest();
                    readRequest.initialize(connectionA, epIn);
                    ByteBuffer readBuffer = ByteBuffer.allocateDirect(MAXPacketSize);
                    readBuffer.compact();
                    ByteBuffer rxBuffer = ByteBuffer.allocate(nSize);
                    long lastCheckTime = System.currentTimeMillis();
                    while (!bUsbReadExit) {
                        long curTime = System.currentTimeMillis();
                        if (curTime - lastCheckTime > 1000) {
                            //1秒检测一次
                            lastCheckTime = curTime;
                            updateUILog("持续监控读线程");
                        }
                        //
                        for (int i = 0; i < nSize; i++) rxBuffer.put(i, (byte) 0);
                        bReadYes = readRequest.queue(rxBuffer, nSize);
                        if ((connectionA != null) && (readRequest != null) && bReadYes) {
                            UsbRequest tempReq = connectionA.requestWait();
                            //检查是否要退出读线程
                            if (bUsbReadExit) break;
                            if (tempReq == readRequest) {
                                synchronized (strUsbReadRunning) {
                                    //TODO:待处理,判断数据空的话不处理
                                    readBuff = Arrays.copyOfRange(rxBuffer.array(), 0, nSize);
                                    if (readBuff[1] == (byte) 0xC1 || readBuff[1] == (byte) 0xC2 || readBuff[1] == (byte) 0xF1) {
                                        short len = 0;
                                        len += (readBuff[2] & 0xFF);
                                        len += (readBuff[3] & 0xFF) << 8;
                                        //有数据
                                        byte[] buff = new byte[len];
                                        Arrays.fill(buff, (byte) 0);
                                        switch (readBuff[1]) {
                                            case (byte) 0xC1:
                                                System.arraycopy(readBuff, 4, buff, 0, len);
                                                liangjibuffer = "";
                                                liangjibuffer = new String(buff);
                                                nLength = len;
                                                break;
                                            case (byte) 0xC2:
                                                System.arraycopy(readBuff, 9, buff, 0, 256);
                                                bFile = readBuff[4] == (byte) 0x01 ? true : false;
                                                //Collections.addAll(liangjibuffer, buff);
                                                liangjibuffer = "";
                                                nLength = 0;
                                                recFileLength = 0;
                                                for (int i = 0; i < 4; i++) {
                                                    int shift = i * 8;
                                                    nLength += (readBuff[i + 5] & 0xFF) << shift;
                                                }
                                                if (bFile) {
                                                    updateUILog("===收到文件头信息：长度：length:" + nLength);
                                                } else {
                                                    updateUILog("===收到数据头信息：长度：length:" + nLength);
                                                }
                                                break;
                                            case (byte) 0xF1:
                                                System.arraycopy(readBuff, 4, buff, 0, len);
                                                if (!bFile) {
                                                    //不是文件就添加到全局变量字符串中
                                                    liangjibuffer = liangjibuffer + new String(buff);
                                                } else {
                                                    //文件，累加长度
                                                    recFileLength += len;
                                                    if (recFileLength == nLength) {
                                                        updateUILog("=====文件接收完毕=======：length:" + recFileLength);
                                                    }
                                                    long curTime2 = System.currentTimeMillis();
                                                    if (curTime2 - lastFilePrintTime > 10000) {
                                                        updateUILog("=====已经接收的文件长度，10秒打印一次：" + recFileLength);
                                                        lastFilePrintTime = curTime;
                                                    }
//                                                    if (len != 508) {f
//                                                        updateUILog("=====已经接收完毕：" + recFileLength);
//                                                    }
                                                }
                                                break;
                                        }
                                        //todo
//                                        String a = new String(buff);
//                                        updateUILog("收到数据:[" + readBuff[1] + "]" + " len=>" + len + " length: " + nLength + " str=>" + a + "\n");
                                        if (liangjibuffer.getBytes("UTF-8").length == nLength && nLength != 0) {
                                            if (nLength > 508)
                                                updateUILog("收到完整数据: " + " length=>" + nLength + "\n");
                                            else
                                                updateUILog("收到完整数据: " + " length=>" + nLength + " str=>" + liangjibuffer + "\n");
                                            JSONObject json = null;
                                            try {
                                                json = JsonUtils.toJsonObject(liangjibuffer);
                                                if (((String) json.get("type")).contains("device")) {
                                                    JSONObject data = (JSONObject) json.get("data");
                                                    if (((String) data.get("cmd")).equals("authorized")) {
                                                        switch (((int) data.get("status"))) {
                                                            case 0:
                                                                //初始化socket,修改为连接前先断开
                                                                initSocket();
                                                                break;
                                                            case 1:
//                                                                SocketManager.sendAuthorizeMsg((String) data.get("authorized"));
                                                                break;
                                                            case 2:
                                                                //Base64.getMimeDecoder().decode((String)data.get("authorized"));
                                                                break;
                                                            case 3:
                                                                break;
                                                        }

                                                    } else if (((String) data.get("cmd")).equals("init")) {
                                                        String mainVersion = (String) data.get("mainVersion");
                                                        String appVersion = (String) data.get("appVersion");
                                                        runOnUiThread(() -> {
                                                            TVdeviceversion.setText(mainVersion);
                                                            TVappversion.setText(appVersion);
                                                            sendCmdMsg("START");
                                                        });
                                                    } else if (((String) data.get("cmd")).equals("link")) {
                                                        int status = (int) data.get("status");
                                                        runOnUiThread(() -> {
//                                                            TVlinkstatus.setText(status + MainActivity.DEVICESTATUS.getValueByIndex(status));
                                                        });
                                                    }

                                                }
                                                nLength = 0;//清空,方式发过来0个数据重复调用
                                            } catch (Exception e) {
                                                e.printStackTrace();
                                            }
                                        }
                                    }
                                }
                            } else {
                                updateUILog("读线程RequestWait出错\n");
                            }
                        } else {
                            updateUILog("读线程queue出错\n");
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    updateUILog("读线程出错了......" + e.getMessage() + "\n");
                    updateUILog("读线程出错了......" + e.getStackTrace().toString() + "\n");
                    //读线程已退出
                    bUsbReadRunning = false;
                    bUsbReadExit = true;
                }
                //读线程已退出
                bUsbReadRunning = false;
                bUsbReadExit = true;
                //此句一定不能少!!!!!!, 否则原生C++函数会有内存泄漏错误
                if ((okUsbReq != null) && (okUsbReq.getEndpoint() != null)) {
                    okUsbReq.close();
                }
                updateUILog("!!!!!!读线程已结束!!!!!!\n");
            }
        }).start();
    }


    //完成某一次正确传输(CT)的读取线程, 当本次传输已正确完成后应及时退出
    //HID设备的读取线程类  (使用UsbRequest方式即异步方式,适用于端点类型为Interrupt或Bulk的传输)
    private void startWriteThread() {
        //直接创建并启动一个匿名线程接口类的实例
        new Thread(new Runnable() {
            //立即开始本次传输的标记
            boolean bFireFlag = false;
            int nSize = MAXPacketSize;
            //检测队列是否空的时间
            long lastCheckTime = System.currentTimeMillis();
            //上次大小
            long lastSize = 0;

            @Override
            public void run() {
                try {
                    updateUILog("开始监听写线程");
//                    //读线程正在运行的标记
                    bUsbReadRunning = true;
                    //读线程用的Usb请求类
                    okUsbReq = new UsbRequest();
                    while (!bUsbReadExit) {
                        //写操作
                        long curTime = System.currentTimeMillis();
                        if (curTime - lastCheckTime > 1000) {
                            //1秒检测一次
                            lastCheckTime = curTime;
                            updateUILog("持续监控写队列：size=" + MQ.size());
                        }
                        synchronized (strUsbWriteRunning) {
                            //不为空，并且上一次已经发送成功
                            if (!MQ.isEmpty() && bUsbWriteOK) {
                                if (MQ.size() > 8) {
                                    bulkMessage(MQ.poll(), MQ.poll(), MQ.poll(), MQ.poll(), MQ.poll(), MQ.poll(), MQ.poll(), MQ.poll());
                                } else {
                                    bulkMessage(MQ.poll());
                                }
                            }
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    updateUILog("写线程出错了......" + e.getMessage() + "\n");
                    //读线程已退出
                    bUsbReadRunning = false;
                    bUsbReadExit = true;
                }   // try  ......  end
//读线程已退出
                bUsbReadRunning = false;
                bUsbReadExit = true;
                //此句一定不能少!!!!!!, 否则原生C++函数会有内存泄漏错误
                if ((okUsbReq != null) && (okUsbReq.getEndpoint() != null)) {
                    okUsbReq.close();
                }
                updateUILog("!!!!!!写线程已结束!!!!!!\n");
            }
        }).start();
    }


    private void writeString(UMessage uMessage) {
        //空标记
        okUsbReq.setClientData("");
        //将writeBuff复制过来
        writeByteBuffer.clear();
        writeByteBuffer.put(uMessage.data);
        writeByteBuffer.rewind();
        //若initialize()返回真,则表示UsRequest对象b打开成功,内存资源已分配给了它,使用完后一定要close()它,切记!!!!!!
        if (okUsbReq.initialize(connectionA, epOut)) {
            //提示说： 这一句已经过时了，其实并不是！！！
            okUsbReq.queue(writeByteBuffer, MAXPacketSize);
            if (connectionA.requestWait() == okUsbReq) {
                okUsbReq.setClientData("Write-JGB01-Cmd-OK");
                if (writeByteBuffer.array()[0] != 0) {
                    if (uMessage instanceof UMessageWithCallBack) {
                        UMessageWithCallBack uMessageWithCallBack = (UMessageWithCallBack) uMessage;
                        uMessageWithCallBack.callBack.onComplete(1);
                    }
                }
            }
        }
    }

    //监视 USB写出的线程 (使用UsbRequest方式即异步方式,适用于端点类型为Interrupt或Bulk的传输)
    //在usb出端点上发送字符串
    private void writeString2(UMessage uMessage) {
        //本APP的接收和发送都采用GBK编码,与通讯另一端的单片机或其它windows Port控制台软件一致.
        //这样确保了汉字的发送也是正常的
        Arrays.fill(writeBuff, (byte) 0);
        writeBuff = uMessage.data;
        //空标记
        okUsbReq.setClientData("");
//        bUsbWriteOK = false;
        //从字节数组中创建ByteBuffer
        ByteBuffer txBuffer = ByteBuffer.allocate(MAXPacketSize + 2);
        //将writeBuff复制过来
        txBuffer.rewind();
        txBuffer.put(writeBuff);
        txBuffer.rewind();
        //若initialize()返回真,则表示UsRequest对象b打开成功,内存资源已分配给了它,使用完后一定要close()它,切记!!!!!!
        if (okUsbReq.initialize(connectionA, epOut)) {
            //提示说： 这一句已经过时了，其实并不是！！！
            okUsbReq.queue(txBuffer, MAXPacketSize);
            if (connectionA.requestWait() == okUsbReq) {
                okUsbReq.setClientData("Write-JGB01-Cmd-OK");
                if (txBuffer.array()[0] != 0) {
//                    bUsbWriteOK = true;
                    if (uMessage instanceof UMessageWithCallBack) {
                        UMessageWithCallBack uMessageWithCallBack = (UMessageWithCallBack) uMessage;
                        uMessageWithCallBack.callBack.onComplete(1);
                    }
                }
            }
        }
        //todo
//        bulkMessage(uMessage);
    }

    /**
     * 写数据，可以一次写1-多个包
     * <p>
     * 批量和单个发送，貌似速度差不多
     * <p>
     * 6M文件大概288秒传输完毕
     * <p>
     * 传输过去的会被传输回来，相当于是传输两次，如果只是单方向传输，是否速度更快
     *
     * @param msgList
     */
    private void bulkMessage(UMessage... msgList) {
        bUsbWriteOK = false;
        int size = msgList.length;
        byte[] toWrite = new byte[MAXPacketSize * size];
        for (int i = 0; i < size; i++) {
            UMessage uMessage = msgList[i];
            System.arraycopy(uMessage.data, 0, toWrite, i * MAXPacketSize, MAXPacketSize);
        }
        int ret = connectionA.bulkTransfer(epOut, toWrite, toWrite.length, 0);
        if (ret > 0) {
            //发送成功标记
            bUsbWriteOK = true;
            if (size == 1) {
                UMessage uMessage = msgList[0];
                if (uMessage instanceof UMessageWithCallBack) {
                    UMessageWithCallBack uMessageWithCallBack = (UMessageWithCallBack) uMessage;
                    uMessageWithCallBack.callBack.onComplete(1);
                }
            } else {
                //多个包，返回最后一个包返回成功
                UMessage lastMessage = msgList[size - 1];
                if (lastMessage instanceof UMessageWithCallBack) {
                    UMessageWithCallBack uMessageWithCallBack = (UMessageWithCallBack) lastMessage;
                    uMessageWithCallBack.callBack.onComplete(1);
                }
            }
        } else {
            updateUILog("====底层传输失败====ret:" + ret + ",length:" + toWrite.length);
        }
    }

    /**
     * 写数据
     */
    private synchronized void bulkMessage2(UMessage msg) {
        bUsbWriteOK = false;
        int ret = connectionA.bulkTransfer(epOut, msg.data, MAXPacketSize, 0);
        if (ret >= 0) {
            bUsbWriteOK = true;
            if (msg instanceof UMessageWithCallBack) {
                UMessageWithCallBack uMessageWithCallBack = (UMessageWithCallBack) msg;
                uMessageWithCallBack.callBack.onComplete(1);
            }
        } else {
            updateUILog("====底层传输失败====ret:" + ret + ",length:" + msg.data.length);
        }
    }

    //打开USB PortA，成功返回真 （可能需要运行期授权）
    //本代码需放在一个线程内执行
    private boolean execUsbPortA() {
        boolean bSuccess = false;
        deviceA = getDeviceFromDetail();
        if (deviceA == null) {
            updateUILog("此HID设备尚未获得支持!\n");
            return false;
        }
        if (usbManager.hasPermission(deviceA)) {
            updateUILog("已取得此USB设备的授权: " + deviceA + "\n");
            //打开USB总线A设备及对应端口
            execThisDevicePortA();
            bSuccess = true;

        } else {
            updateUILog("未取得此USB设备的授权\n");
            //需取得USB管理权限 ： 运行期授权
            //这里将通过penIntent发送一个广播INTENT_ACTION_GRANT_USB 给广播接收器broadcastReceiver
            usbPermissionA = UsbPermission.Requested;
            usbManager.requestPermission(deviceA, penIntent);

            //这里应该等待授权界面最多30秒后才关闭......
            int timeout = 0;
            while (timeout > 30) {
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                timeout += 1;
                if ((usbPermissionA == UsbPermission.Granted) || (usbPermissionA == UsbPermission.Denied))
                    break;
            }
            //授权OK了，才能打开此设备及对应端口
            if (usbPermissionA == UsbPermission.Granted) {
                updateUILog("已取得此USB设备的授权: " + deviceA + "\n");
                //打开USB总线A设备及对应端口
                execThisDevicePortA();
                bSuccess = true;
            } else {
                updateUILog("未取得此USB设备的授权: " + deviceA + "\n");
                bSuccess = false;
            }
        }
        return bSuccess;
    }

    //打开USB总线A设备及对应端口
    private void execThisDevicePortA() {
        //先打开usb连接
        connectionA = usbManager.openDevice(deviceA);
        //************************ USB设备的核心操作部分 *************************

        if (connectionA != null) {
            interfaceA = deviceA.getInterface(0);
            //usb连接 索取此接口成功后就可取回此接口描述符下的两个端点
            if (connectionA.claimInterface(interfaceA, true)) {
                updateUILog("索取接口OK: " + interfaceA.getId() + "\n" + "接口中定义的端点数: " + interfaceA.getEndpointCount() + "\n");
                for (int i = 0; i < interfaceA.getEndpointCount(); i++) {
                    UsbEndpoint ep = interfaceA.getEndpoint(i);
                    if ((ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) || (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_INT)) {
                        if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
                            epIn = ep;
                            updateUILog("找到了入方向端点: " + ep.getAddress() + "\n");
                        } else {
                            epOut = ep;
                            updateUILog("找到了出方向端点: " + ep.getAddress() + "\n");
                        }
                    }
                }
                updateUILog("打开此USB设备OK\n");
            } else {


                //出错关闭usb连接
                connectionA.close();
                connectionA = null;
                interfaceA = null;

                epOut = null;
                epIn = null;

                return;
            }
        }
    }

    private UsbDevice getDeviceFromDetail() {
        UsbDevice ud = null;
        if (usbManager == null)
            usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
        for (UsbDevice v : usbManager.getDeviceList().values()) {
            if (!getChipType(v.getVendorId(), v.getProductId()).contains("Unknown")) {
                ud = v;
                break;
            }
        }
        return ud;
    }

    private String getChipType(int nVID, int nPID) {
        String strChip = "Unknown";
        switch (nVID) {
            case 1317:
                if (nPID == 42156)
                    //JGB01开发板
                    strChip = "良机来也";
                break;
        }
        return strChip;
    }

    public void updateUILog(String logtext) {
        runOnUiThread(() -> {
            editRead.append(logtext + "\n");
        });
    }
}